package com.wn.cl.park.service.impl;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alipay.api.AlipayClient;
import com.alipay.api.domain.AlipayTradePagePayModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wn.cl.park.config.AlipayConfig;
import com.wn.cl.park.mapper.OrderMapper;
import com.wn.cl.park.mapper.PaymentsMapper;
import com.wn.cl.park.mapper.ReservationsMapper;
import com.wn.cl.park.model.dto.PayRequest;
import com.wn.cl.park.model.entity.Order;
import com.wn.cl.park.model.entity.Payments;
import com.wn.cl.park.model.entity.Reservations;
import com.wn.cl.park.model.enums.DmhStatus;
import com.wn.cl.park.service.IPaymentsService;
import com.wn.sddfp.common.exception.Assert;
import com.wn.sddfp.common.result.enums.impl.BusinessCode;
import lombok.SneakyThrows;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author yellow docker
 * @since 2025-03-11
 */
@Service
public class PaymentsServiceImpl extends ServiceImpl<PaymentsMapper, Payments> implements IPaymentsService {



    @Autowired
    private AlipayClient alipayClient;   //支付宝提供的客户端
    @Autowired
    private AlipayConfig alipayConfig;   //使用自定义配置类与Alipay中一个类同名

    @Autowired
    private PaymentsMapper paymentsMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private ReservationsMapper reservationsMapper;

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private RabbitTemplate rabbitTemplate;
    /**
     * 创建交易页面的支付请求对象
     */

    @Override
    @Transactional
    public String pay(PayRequest request) {
        String uniqueCode = request.getUniqueCode();
        String orderId = request.getOrderId();
        Boolean isSet = redisTemplate.opsForValue().setIfAbsent(uniqueCode, "processing", 60, TimeUnit.MINUTES);
        Assert.error(ObjectUtil.isNull(isSet), BusinessCode.FAILED);
        if (!isSet) {
            // 如果唯一编码已存在，直接返回之前的结果
            String previousResult = (String) redisTemplate.opsForValue().get(uniqueCode);
            Assert.error(ObjectUtil.isNull(previousResult), BusinessCode.FAILED);
            return previousResult;
        }
        try {
            Reservations reservations = reservationsMapper.selectById(orderId);
            //创建支付记录
            Payments payments = new Payments();
            payments.setReservationId(reservations.getId());
            payments.setAmount(reservations.getAmount());
            payments.setPaymentStatus(DmhStatus.PAYMENTS_PAYING.getCode());
            //生成订单编号
            long orderIdTemp = IdUtil.getSnowflake(1, 1).nextId();
            String orderNum = "RESERVATION_" + orderIdTemp;
            payments.setPaymentNumber(orderNum);
            paymentsMapper.insert(payments);


            //通过id查询订单
            AlipayTradePagePayRequest aliRequest = getAlipayTradePagePayRequest(payments);
            //调用SDK生成表单
            String form = alipayClient.pageExecute(aliRequest).getBody();

            // 将处理结果存储到Redis中
            redisTemplate.opsForValue().set(uniqueCode, form);
            return form;
        } catch (Exception e) {
            // 如果支付过程中出现异常，删除Redis中的标记以允许重试
            log.error("支付失败"+e.getMessage());
            redisTemplate.delete(uniqueCode);
            throw new RuntimeException("支付异常", e);
        }
    }

    //支付宝异步回调
    @Override
    @SneakyThrows
    public void aliPayNotify(HttpServletRequest request) {
        //获取所有请求参数，重新创建一个Map再封装一次数据
        Map<String, String> params = request.getParameterMap().entrySet().stream()
                .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue()[0]));
        // 验证签名
        String sign = params.get("sign");
        String contentV1 = AlipaySignature.getSignCheckContentV1(params);
        boolean rsa256CheckSignature = AlipaySignature.rsa256CheckContent(contentV1,
                sign, alipayConfig.getAlipayPublicKey(), "UTF-8");


        //签名验证失败
        Assert.error(!rsa256CheckSignature, BusinessCode.FAILED);

        //out_trade_no即订单ID
        Long payId = Long.valueOf(params.get("out_trade_no"));
        Payments payments = paymentsMapper.selectById(payId);
        //表示支付成功
        if ( "TRADE_SUCCESS".equals(params.get("trade_status"))) {
            // 签名验证成功 并且 支付宝回调的状态是成功状态 TRADE_SUCCESS
            // 支付成功，修改数据库中该订单的状态，out_trade_no即订单ID

            //更新支付状态
            payments.setPaymentStatus(DmhStatus.PAYMENTS_PAY_SUCCESS.getCode());
            paymentsMapper.updateById(payments);
            //更新预订单状态
            Reservations reservations = reservationsMapper.selectById(payments.getReservationId());
            reservations.setStatus(DmhStatus.RESERVATIONS_PAY.getCode());
            reservations.setPaymentTime(LocalDateTime.now());
            reservationsMapper.updateById(reservations);
            //更新订单表状态
            Order order = orderMapper.selectById(reservations.getOrderId());
            order.setState(DmhStatus.ORDER_PAY_SUCCESS.getCode());

            Map<String, Object> messageMap = new HashMap<>();
            messageMap.put("userId", reservations.getUserId());
            messageMap.put("reservationId", reservations.getId());
            //消息提醒
            rabbitTemplate.convertAndSend(
                    "delayed-exchange",  // 交换机名称
                    "message.delay",         // 路由键
                    messageMap,            // 消息体
                    message -> {
                        // 设置延迟时间：25分钟
                        message.getMessageProperties().setHeader("x-delay", 1500000);
                        return message;
                    });
            //超时未入场
            rabbitTemplate.convertAndSend(
                    "delayed-exchange",  // 交换机名称
                    "timeout.delay",         // 路由键
                    reservations.getId(),            // 消息体（预定表ID）
                    message -> {
                        // 设置延迟时间：30分钟
                        message.getMessageProperties().setHeader("x-delay", 1800000);
                        return message;
                    });

        }
        //支付失败逻辑
        //修改支付表状态为支付失败
        payments.setPaymentStatus(DmhStatus.PAYMENTS_PAY_FAIL.getCode());
        paymentsMapper.updateById(payments);
        //发送mq队列或者远程调用站内消息的窗口，发送消息提醒消费者支付失败



    }

//支付宝支付请求设置
    private AlipayTradePagePayRequest getAlipayTradePagePayRequest(Payments payments) {
        //1.准备支付的参数，包括需要支付的订单的id，价格，物品名称
        AlipayTradePagePayModel model = new AlipayTradePagePayModel();
        model.setOutTradeNo(payments.getId().toString()); // 需要支付的订单id，自定义的订单id，不能重复，唯一，已经支付的无法继续支付
        model.setTotalAmount(payments.getAmount().toString()); // 需要支付的钱 model.setTotalAmount("88.88");
        model.setSubject("预约订单"); // 要支付的物品，比如 model.setSubject("Iphone6 16G");
        model.setProductCode("FAST_INSTANT_TRADE_PAY");  //销售产品码，电脑支付场景就使用FAST_INSTANT_TRADE_PAY
        // 2.创建支付的请求，设置上面的准备支付的参数
        AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
        request.setBizModel(model);
        // 3.设置支付宝异步回调，这个需要用内网穿透
        request.setNotifyUrl(alipayConfig.getNotifyUrl());
        // 4.设置支付宝支付成功返回的页面，这里让支付成功直接回到static下的一个静态页面中
        request.setReturnUrl(alipayConfig.getReturnUrl());
        return request;
    }


}
